/**   
 * @Title: WebUtils.java
 * @Package com.jbeer.framework.utils
 * @author Bieber
 * @date 2014-2-22 下午01:43:44
 * @version V1.0   
 */

package com.jbeer.framework.utils;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.channels.Channels;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
import java.nio.channels.ReadableByteChannel;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.Part;

import com.jbeer.framework.JBeer;
import com.jbeer.framework.constant.JBeerConstant;
import com.jbeer.framework.web.JBeerWebContext;

/**
 * <p>
 * 类功能说明:处理web请求的工具
 * </p>
 * <p>
 * 类修改者 修改日期
 * </p>
 * <p>
 * 修改说明
 * </p>
 * <p>
 * Title: WebUtils.java
 * </p>
 * 
 * @author Bieber <a
 *         mailto="bieber.jbeer@hotmail.com">bieber.jbeer@hotmail.com</a>
 * @date 2014-2-22 下午01:43:44
 * @version V1.0
 */

public class WebUtils {

    /**
     * 
    * <p>函数功能说明: 从request获取上传的文件</p>
    * <p>Bieber  2014-3-2</p>
    * <p>修改者名字 修改日期</p>
    * <p>修改内容</a>  
    * @return Map<String,File>
     */
    public static Map<String, Object> getParameterForUpload(HttpServletRequest request,
                                                            String tempDir) throws IOException {
        Map<String, Object> parameterMaps = new HashMap<String, Object>();
        List<File> tempFiles = new ArrayList<File>();
        //获取请求的输入流
        ServletInputStream inputStream = request.getInputStream();
        //解析HTTP请求的头内容，从而判断是否是上传文件格式
        String contentType = request.getContentType();
        if (contentType == null || !contentType.contains(JBeerConstant.UPLOAD_FILE_CONTENTTYPE)) {
            return parameterMaps;
        }
        File tempFile = null;
        String paramName = null;
        String fileName = null;
        String[] items = null;
        String boundary = null;
        byte[] lineBuffer = new byte[1024];
        ByteArrayOutputStream lineOutputStream = null;
        ByteArrayOutputStream textParameterOutputStream = null;
        contentType = contentType.replaceAll("[\\s\"]{1,}", "");
        String[] contentTypeItems = contentType.split(";");
        try {
            /**
             * 获取HTTP头内容中分隔符
             */
            for (String contentTypeItem : contentTypeItems) {
                if (contentTypeItem.startsWith(JBeerConstant.HTTP_BOUNDARY_NAME)) {
                    boundary = contentTypeItem
                        .substring(JBeerConstant.HTTP_BOUNDARY_NAME.length() + 1);
                }
            }
            int readLength = -1;
            int bufferSize = 1024;
            String lineStr = null;
            FileOutputStream fos = null;
            boolean newParameter = false;
            boolean isTextParameter = true;
            if (contentType.contains(JBeerConstant.UPLOAD_FILE_CONTENTTYPE)) {
                /**
                 * 通过次方法获取输入流的一行字节码
                 */
                readLength = inputStream.readLine(lineBuffer, 0, bufferSize);
                /**
                 * 循环获取输入内容
                 */
                while (readLength > 0) {
                    /**
                     * 此处通过判断读取的字节数量是否放慢缓存来表示是否读完了一行，如果小于，表示已经读完一行，否则表示一行还未读完，需要继续读取
                     */
                    if (readLength < bufferSize) {
                        if (lineOutputStream == null) {
                            lineOutputStream = new ByteArrayOutputStream();
                        }
                        lineOutputStream.write(lineBuffer, 0, readLength);
                        /**
                         * 解析一行的内容字符串
                         */
                        lineStr = lineOutputStream.toString(JBeer.applicationEncode);
                        lineOutputStream.flush();
                        lineOutputStream.reset();
                    } else {
                        if (lineOutputStream == null) {
                            lineOutputStream = new ByteArrayOutputStream();
                        }
                        lineOutputStream.write(lineBuffer, 0, readLength);
                    }
                    /**
                     * 解析一行的内容从而判断当前读取的内容，进行相应的处理
                     */
                    if (lineStr.startsWith(JBeerConstant.UPLOAD_FILE_DESPOSITION)) {
                        lineStr = lineStr.replaceAll("[\\s\"]{1,}", "");
                        items = lineStr.split(JBeerConstant.HTTP_SPLIT_FLAG);
                        for (String item : items) {
                            if (item.startsWith(JBeerConstant.UPLOAD_FILE_NAME)) {
                                fileName = item
                                    .substring(JBeerConstant.UPLOAD_FILE_NAME.length() + 1);
                                //fileName = new String(fileName.getBytes("ISO8859-1"),JBeerConfiguration.applicationEncode);
                            } else if (item.startsWith(JBeerConstant.UPLOAD_PARAMATER_NAME)) {
                                paramName = item.substring(JBeerConstant.UPLOAD_PARAMATER_NAME
                                    .length() + 1);
                            }
                        }
                        newParameter = true;
                        readLength = inputStream.readLine(lineBuffer, 0, bufferSize);
                        continue;
                    } else if (lineStr.startsWith(JBeerConstant.UPLOAD_FILE_CONTENTTYPE_HEAD)) {
                        isTextParameter = false;
                        readLength = inputStream.readLine(lineBuffer, 0, bufferSize);
                        continue;
                    } else if (lineStr.contains(boundary)) {//当读取到一个分隔符，表示是一个字段的开始或者结束
                        if (fos != null) {
                            fos.flush();
                            fos.close();
                            fos = null;
                        }
                        if (newParameter && isTextParameter && textParameterOutputStream != null) {
                            String value = textParameterOutputStream
                                .toString(JBeer.applicationEncode);
                            textParameterOutputStream.flush();
                            textParameterOutputStream.reset();
                            addParametervalue(parameterMaps, paramName,
                                value.replaceAll("\r\n", ""));
                        }
                        isTextParameter = true;
                        readLength = inputStream.readLine(lineBuffer, 0, bufferSize);
                        continue;

                    } else if (lineStr.length() <= 0 || lineStr.equals("\r\n")) {//读取到换行符则不做处理
                        readLength = inputStream.readLine(lineBuffer, 0, bufferSize);
                        continue;
                    } else {
                        if (!isTextParameter) {
                            if (newParameter && readLength > 0) {
                                tempFile = new File(new File(tempDir), fileName);
                                fos = new FileOutputStream(tempFile);
                                newParameter = false;
                                addParametervalue(parameterMaps, paramName, tempFile);
                                tempFiles.add(tempFile);
                            }
                            fos.write(lineBuffer, 0, readLength);
                        } else {
                            if (textParameterOutputStream == null) {
                                textParameterOutputStream = new ByteArrayOutputStream();
                            }
                            textParameterOutputStream.write(lineBuffer, 0, readLength);
                        }
                        readLength = inputStream.readLine(lineBuffer, 0, bufferSize);
                    }
                }
            }
        } finally {
            if(inputStream!=null){
                inputStream.close();
            }
            if(lineOutputStream!=null){
                lineOutputStream.close();
            }
            if(textParameterOutputStream!=null){
                textParameterOutputStream.close();
            }
        }
        JBeerWebContext.setTempFiles(tempFiles);
        return parameterMaps;
    }

    /**
     * 
    * <p>函数功能说明:将解析到HTTP请求的参数放到map对应参数的数组中</p>
    * <p>Bieber  2014-3-8</p>
    * <p>修改者名字 修改日期</p>
    * <p>修改内容</a>  
    * @return void
     */
    public static void addParametervalue(Map<String, Object> parameterMap, String paraName,
                                         Object value) {
        if (parameterMap.get(paraName) != null) {
            Object[] paraValues = (Object[]) parameterMap.get(paraName);
            Object[] dest = new Object[paraValues.length + 1];
            System.arraycopy(paraValues, 0, dest, 0, paraValues.length);
            dest[paraValues.length] = value;
            parameterMap.put(paraName, dest);
        } else {
            Object[] values = new Object[1];
            values[0] = value;
            parameterMap.put(paraName, values);
        }
    }

    public static File getRequestPartToTempFile(String tempDir, Part part) throws IOException {
        File file = new File(tempDir + "/" + part.getName());
        if (!file.exists()) {
            file.createNewFile();
        }

        FileOutputStream fout = new FileOutputStream(file);
        FileChannel outChannel = fout.getChannel();
        ReadableByteChannel readableChannel = Channels.newChannel(part.getInputStream());
        FileLock fileLock = outChannel.lock();
        try {
            outChannel.transferFrom(readableChannel, 0, part.getSize());
        } finally {
            fileLock.release();
            outChannel.close();
            fout.close();
            readableChannel.close();
        }
        return file;
    }

    public static void sendError(int code, Throwable e) throws IOException {
        HttpServletResponse response = JBeerWebContext.getResponse();
        if (response != null) {
            response.sendError(code, e.getMessage());
        }
    }

    public static void sendError(int code, String message) throws IOException {
        HttpServletResponse response = JBeerWebContext.getResponse();
        if (response != null) {
            response.sendError(code, message);
        }
    }

    /*private static String generateErrorMessage(int level, Throwable e) {
    	StringBuffer blank = new StringBuffer();
    	for (int i = 0; i < level; i++) {
    		blank.append(" ");
    	}
    	StringBuffer exceptionMessage = new StringBuffer();
    	exceptionMessage.append(e.getMessage());
    	StackTraceElement[] elements = e.getStackTrace();
    	for (StackTraceElement element : elements) {
    		exceptionMessage.append(element.getClassName())
    				.append(element.getMethodName())
    				.append(element.getLineNumber()).append("<br/>");
    	}
    	if (e.getCause() != null) {
    		exceptionMessage.append(generateErrorMessage(level + 1,
    				e.getCause()));
    	}
    	return exceptionMessage.toString();
    }*/
}
